home *** CD-ROM | disk | FTP | other *** search
/ The PC-SIG Library 10 / The PC-Sig Library - Shareware for the IBM PC and Compatibles (PC-SIG)(Tenth Edition Disks 1-2804)(1991).iso / PC_SIGCD / 05 / 6 / DISK0564.ZIP / SOURCE.ARC / TAIL.ASM < prev    next >
Assembly Source File  |  1988-07-09  |  14KB  |  493 lines

  1.         TITLE TAIL - A FILTER FOR MSDOS2
  2.         PAGE 55,132
  3. ;**********************************************************************
  4. ;       THIS PROGRAM PRINTS THE LAST FEW LINES OF A TEXT FILE.
  5. ;
  6. ;       USAGE:  TAIL -n filename
  7. ;               -n is optional, limits output to n lines (20 default)
  8. ;
  9. ;       BY: JON DART
  10. ;           3012 HAWTHORN ST.,
  11. ;           SAN DIEGO, CA 92104
  12. ;
  13. ;    VERSION 1.8: 02-OCT-87 ASSEMBLES UNDER MASM 5.0
  14. ;    VERSION 1.7: 10-JAN-87 HANDLES AMBIG. FILE NAMES, MULTIPLE FILES
  15. ;    VERSION 1.6: 14-AUG-86 HANDLES -n UP TO 65535, NOW BUFFERS OUTPUT
  16. ;    VERSION 1.5: 06-JUL-86 CHANGES TO MEMORY ALLOC, + NOW ASSEMBLES UNDER
  17. ;             MASM 4.0
  18. ;       VERSION 1.4: 04-FEB-86 FIXED BUG, NOW READS FROM STDIN CORRECTLY
  19. ;       VERSION 1.3: 16-JAN-86 MORE KOSHER MEMORY USAGE, NOW .EXE FILE
  20. ;       VERSION 1.2: 27-SEP-85 USES STD. INPUT IF NO FILE NAME GIVEN
  21. ;
  22. ;       CONVERTED FROM CP/M-80 TO MSDOS, 16-SEP-85
  23. ;
  24. ;       VERSION 1.1: 15-MAR-85
  25. ;       VERSION 1.0: 15-JAN-85
  26. ;
  27. ;   TO BUILD TAIL.EXE:
  28. ;    MASM TAIL,TAIL,NUL,NUL
  29. ;    LINK TAIL,TAIL,NUL,ASM
  30.  
  31. INBUFSIZE EQU   8192                    ;SIZE OF INPUT BUFFER
  32. OUTBUFSIZE EQU    512            ;SIZE OF OUTPUT BUFFER
  33. MAXARGS    EQU    40            ;MAX. # COMMAND LINE ARGUMENTS
  34. PRGSIZE    EQU     800H            ;MAX. SIZE OF PROGRAM + FIXED DATA
  35.  
  36.         .XLIST
  37.         INCLUDE ASCII.DEF
  38.         INCLUDE MSDOS2.DEF
  39.     INCLUDE MACROS.DEF
  40.         .LIST
  41.  
  42. ERROR   MACRO   ERRNUM                  ;SHOW ERROR MESSAGE
  43.     PUSH    DS
  44.     MOV    AX,DGROUP
  45.     MOV    DS,AX
  46.         MOV     DX,OFFSET MSG&ERRNUM
  47.     CALL    ERRORMSG
  48.     POP    DS
  49.         ENDM
  50.  
  51.     DOSSEG
  52.     .MODEL     SMALL
  53.  
  54. ;       MEMORY DEFINITIONS:
  55. ;
  56.     .DATA
  57. ENDTXT  DW      1 DUP (?)               ;OFFSET TO END OF TEXT IN INPUT BUFFER
  58. NREAD   DW      1 DUP (?)               ;NUMBER OF BYTES READ
  59. SIZEHI  DW      1 DUP (?)               ;HI WORD OF FILE SIZE
  60. SIZELO  DW      1 DUP (?)               ;LO WORD OF FILE SIZE
  61. POSHI    DW    1 DUP (?)        ;HI WORD OF FILE POSITION
  62. POSLO    DW    1 DUP (?)        ;LO WORD OF FILE POSITION
  63. NUMARGS    DW    1 DUP (?)        ;NUMBER OF COMMAND LINE ARGUMENTS
  64. INHANDLE DW     0                       ;INPUT FILE HANDLE
  65.                                         ;(STD. INPUT BY DEFAULT)
  66. NUMLIN  DW      20                      ;NUMBER OF LINES TO LIST
  67. NUMCNT    DW    1 DUP (?)        ;COUNTS NUMBER OF LINES TO GO
  68. ONEFILE    DB    1            ;FLAG, SET 0 WHEN >1 FILE
  69. ATSTART DB    0            ;FLAG, SET <>0 WHEN AT START OF FILE
  70. AMTTOREAD DW    INBUFSIZE        ;AMOUNT TO READ ON NEXT READ OP
  71. OUTNDX    DW    0            ;INDEX TO NEXT FREE SLOT IN OUTPUT BUFFER
  72. MSG1    DB      CR,LF,"tail: can't open: ",0
  73. MSG1E   DB      CR,LF,0
  74. MSG2    DB      CR,LF,"tail: read error.",CR,LF,0
  75. MSG4    DB    CR,LF,"tail usage: tail -n file1 file2 ...",CR,LF,0
  76. MSG5    DB    CR,LF,"tail: too many command line arguments",CR,LF,0
  77. MSG6    DB    CR,LF,"tail: unknown pathname ",0
  78.  
  79.     .STACK
  80.         DB      512 DUP (?)
  81.  
  82. ;    UNINITIALIZED DATA:
  83.  
  84.     .DATA?
  85. INBUF    DB      INBUFSIZE DUP (?)    ;INPUT BUFFER
  86. OUTBUF    DB      OUTBUFSIZE DUP (?)    ;OUTPUT BUFFER
  87. PREFIX    DB      65 DUP (?)             ;DRIVE/DIRECTORY PREFIX
  88. SPATH    DB      65 DUP (?)        ;SEARCH PATH
  89. FILENAME DB     65 DUP (?)        ;FILE NAME
  90. ARGPTRS DB     (2*MAXARGS) DUP (?)    ;POINTERS TO COMMAND LINE ARGUMENTS
  91. ARGBUF    DB     300 DUP (?)          ;BUFFER FOR COMMAND LINE ARGUMENTS
  92. DTA    DB      128 DUP (?)        ;DATA TRANSFER AREA FOR DOS
  93. MAXMEM    EQU    DTA+128
  94.  
  95.     .CODE
  96.         EXTRN   SKIPSP:NEAR,DTOBIN:NEAR,CPYCNT:NEAR
  97.         EXTRN   ERRORMSG:NEAR,TYPTX:NEAR,COUT:NEAR
  98.     EXTRN    FIXPATH:NEAR,GETARGS:NEAR,TYPE_UFN:ABS,TYPE_UNK:ABS
  99.  
  100. ENTRY:
  101.         TEST_DOS2                       ;TEST FOR DOS 2.0, EXIT IF DOS 1
  102. MEMOK:  
  103.     MOV    AX,DGROUP
  104.     MOV    ES,AX              ;SET EXTRA SEG TO POINT TO DATA
  105.         MOV     BX,(80H)             ;GET BYTE COUNT FOR COMMAND LINE
  106.         CMP     BYTE PTR [BX],0         ;TEST IT
  107.         JNE     L_1                     ;IF NOT 0
  108.     MOV    DS,AX
  109.         JMP     START            ;NO ARGUMENTS, USE STDIN
  110. L_1:
  111.         PUSH    BX
  112.         MOV     DL,BYTE PTR [BX]
  113.         MOV     DH,0
  114.         ADD     BX,DX
  115.         INC     BX
  116.         MOV     BYTE PTR [BX],0         ;PUT 0 BYTE AT END OF COMMAND LINE
  117.         POP     BX
  118.         INC     BX            ;POINT TO START OF COMMAND LINE
  119.     MOV    SI,OFFSET ARGPTRS
  120.     MOV    DI,OFFSET ARGBUF
  121.     MOV    CX,MAXARGS
  122.     CALL    GETARGS            ;COLLECT COMMAND LINE ARGUMENTS
  123.     JNB    SHORT L_2        ;IF OK
  124.         ERROR   5                    ;TOO MANY ARGUMENTS
  125.         JMP     EXIT2
  126. L_2:
  127.     MOV    AX,DGROUP
  128.     MOV    DS,AX            ;SET DATA SEG
  129.     MOV    WORD PTR NUMARGS,CX    ;SAVE # OF ARGUMENTS
  130.     CMP    CX,0
  131.     JNE    SHORT L_2A        ;IF SOME ARGUMENT
  132.     JMP    START            ;NO ARGUMENTS, USE STDIN
  133. L_2A:
  134.     MOV    SI,OFFSET ARGPTRS
  135.     MOV    BX,WORD PTR [SI]    ;POINT TO 1ST ARGUMENT
  136.     MOV    AL,BYTE PTR [BX]    ;GET 1ST CHAR.
  137.         CMP     AL,'-'
  138.         JE      L_3                     ;IF SWITCH SPECIFIED
  139.     MOV    SI,OFFSET ARGPTRS
  140.     MOV    CX,WORD PTR NUMARGS    ;GET # OF ARGUMENTS
  141.         JMP     GETFILES        ;IF NO SWITCH
  142. L_3:
  143.         INC     BX
  144.         MOV     CL,0
  145.         PUSH    BX
  146. CD:     MOV     AL,BYTE PTR [BX]         ;HAVE NUMBER, COUNT NUMBER OF DIGITS
  147.         CMP     AL,'0'
  148.         JC      NODGT
  149.         CMP     AL,'9'+1
  150.         JNC     NODGT
  151.         INC     BX
  152.         INC     CL
  153.         JMP     SHORT CD
  154. NODGT:
  155.         POP     BX
  156.         MOV     CH,0                    ;CL HOLDS DIGIT COUNT
  157.         CALL    DTOBIN                  ;CONVERT NUMBER TO BINARY
  158.         JNC     L_4                     ;IF OK
  159.     JMP    SHORT USE
  160. L_4:
  161.         CMP     AX,0                    ;IS NUMBER 0?
  162.         JNE     NOT0                    ;NO.
  163.         JMP     EXIT2                   ;YES, IT IS, JUST EXIT
  164. NOT0:
  165.         MOV     WORD PTR NUMLIN,AX      ;STORE # LINES
  166.     MOV    SI,OFFSET ARGPTRS+2
  167.     MOV    CX,WORD PTR NUMARGS    ;GET # OF ARGUMENTS
  168.     DEC    CX            ;-1 CAUSE OF SWITCH
  169.     JMP    SHORT GETFILES
  170. USE:
  171.         ERROR   4                    ;TELL USER HOW TO USE
  172.         JMP     EXIT2
  173. START:    
  174.     CALL    TAIL            ;SHOW THE "TAIL"
  175.     JMP    EXIT2
  176. GETFILES:
  177.     MOV    AX,DGROUP
  178.     MOV    DS,AX
  179.     CMP    CX,0            ;NO FILE ARGUMENTS?
  180.     JNE    GOT1
  181.     JMP    START            ;NO, JUST USE STDIN
  182. GOT1:
  183.     CMP    CX,1            ;>1 ARG?
  184.     JE    ONLY1            ;NOPE
  185.     MOV    BYTE PTR ONEFILE,0    ;>1 ARG
  186. ONLY1:
  187. ARGLUP:    MOV    BX,WORD PTR [SI]    ;BX POINTS TO FILE NAME
  188.     PUSH    CX
  189.     PUSH    SI
  190.     CALL    DOARG
  191.     POP    SI
  192.     POP    CX
  193. SKIPSW:
  194.     ADD    SI,2
  195.     LOOP    ARGLUP
  196.     JMP    EXIT2    
  197.  
  198. ;    DOARG = PROCESS 1 ARGUMENT
  199. ;    ES:BX POINTS TO IT
  200.  
  201. DOARG    PROC     NEAR
  202.     MOV    AH,SET_DTA
  203.     MOV    DX,OFFSET DTA
  204.     INT    DOS            ;SET DTA
  205.         MOV    CX,OFFSET SPATH
  206.         MOV    DX,OFFSET PREFIX
  207.         PUSH    BX
  208.         CALL    FIXPATH                 ;PARSE PATHNAME
  209.     POP    BX
  210.     CMP    AL,TYPE_UNK
  211.     JE    BADNAME
  212.     CMP    AL,TYPE_UFN
  213.     JE    GOTNAME            ;IF UNAMBIG. FILE NAME
  214.     MOV    BYTE PTR ONEFILE,0    ;AMBIG. FILE NAME OR DIR, FLAG IT
  215.     JMP    SHORT GOTNAME
  216. BADNAME:
  217.     MOV    DX,OFFSET MSG6
  218.     CALL    ERRORMSG        ;BAD FILE NAME, SHOW MSG.
  219.     MOV    DX,BX
  220.     CALL    ERRORMSG        ;SHOW FILE THAT CAUSED IT
  221.     RET
  222. GOTNAME:
  223.         MOV     DX,OFFSET SPATH            ;POINT TO SEARCH PATH
  224.         MOV     CX,31H                  ;SET SEARCH ATTRIBUTES
  225.         MOV     AH,FIND_FIRST
  226.         INT     DOS                     ;SEARCH FOR 1ST MATCH
  227.     JB    BADNAME            ;IF NOTHING FOUND
  228. GOTFILE:
  229.     MOV    SI,OFFSET PREFIX
  230.     MOV    DI,OFFSET FILENAME
  231.     MOV    CX,65
  232.     CALL    CPYCNT            ;COPY PREFIX TO FILE NAME AREA
  233.         DEC     DI                      ;BACK UP OVER NULL
  234.         MOV     SI,(OFFSET DTA)+30         ;POINT TO FILE NAME WE FOUND
  235.         CMP     [SI],BYTE PTR '.'       ;DOES IT START WITH .? -
  236.         JNE     NOTDOT                  ;- NO
  237.     JMP    SHORT SKIPFILE        ;YES, JUST SKIP IT
  238. NOTDOT:
  239.     CALL    CPYCNT            ;COPY FILE WE FOUND AFTER PREFIX
  240.     CALL    DOFILE            ;DO 1 FILE
  241. SKIPFILE:
  242.         MOV     AH,FIND_NEXT
  243.         INT     DOS                     ;FIND NEXT MATCH, IF ANY
  244.         JC      NOMORE                  ;IF NONE
  245.         JMP     GOTFILE                 ;GOT ONE, BACK TO TOP OF LOOP
  246. NOMORE:
  247.     RET
  248. DOARG    ENDP
  249.  
  250. DOFILE  PROC    NEAR
  251.         MOV     DX,OFFSET FILENAME      ;DX POINTS TO FILE NAME
  252.         MOV     AL,READ_ACCESS
  253.         MOV     AH,DOS2_OPEN
  254.         INT     DOS                     ;TRY TO OPEN FILE
  255.     JB    BADOPN            ;IF ERROR
  256.     MOV    WORD PTR INHANDLE,AX    ;SAVE FILE HANDLE
  257.     CMP    BYTE PTR ONEFILE,1    ;ONE FILE ONLY?
  258.     JE    NOSHOW            ;YES, DON'T SHOW NAME
  259.     CALL    SHOWFILE        ;SHOW FILE NAME
  260. NOSHOW:
  261.     CALL    TAIL            ;SHOW TAIL OF FILE
  262.     RET
  263. BADOPN:
  264.         MOV     DX,OFFSET MSG1
  265.         CALL    ERRORMSG        ;CAN'T OPEN FILE
  266.     MOV    DX,OFFSET FILENAME
  267.     CALL    ERRORMSG        ;SHOW NAME
  268.         MOV     DX,OFFSET MSG1E
  269.         CALL    ERRORMSG        ;SHOW CR/LF
  270.     RET
  271. DOFILE    ENDP
  272.  
  273. ;    SHOW FILE NAME
  274.  
  275. SHOWFILE PROC    NEAR
  276.     MOV    AX,"="
  277.     MOV    CX,5
  278. BARS:
  279.     CALL    WRITEBYTE
  280.     LOOP    BARS
  281.     MOV    AX,SPACE
  282.     CALL    WRITEBYTE
  283.     MOV    BX,OFFSET FILENAME
  284. SHOWF:    MOV    AL,BYTE PTR [BX]
  285.     CMP    AL,0
  286.     JE    ENDF
  287.     CALL    WRITEBYTE
  288.     INC    BX
  289.     JMP    SHOWF    
  290. ENDF:    MOV    AL,SPACE
  291.     CALL    WRITEBYTE
  292.     MOV    AL,'='
  293.     MOV    CX,5
  294. BARS2:
  295.     CALL    WRITEBYTE
  296.     LOOP    BARS2
  297.     MOV    AL,CR
  298.     CALL    WRITEBYTE
  299.     MOV    AL,LF
  300.     CALL    WRITEBYTE
  301.     RET
  302. SHOWFILE ENDP
  303.  
  304. ;    AFTER A FILE HAS BEEN OPENED, THIS PROCEDURE OUTPUTS ITS "TAIL"
  305.  
  306. TAIL    PROC    NEAR
  307.     MOV    BYTE PTR ATSTART,0    ;CLEAR "AT START" FLAG
  308.     MOV    WORD PTR AMTTOREAD,INBUFSIZE  ;SET INITIAL AMOUNT TO READ
  309.     MOV    AX,WORD PTR NUMLIN    ;GET # LINES TO SHOW
  310.     MOV    WORD PTR NUMCNT,AX    ;INIT COUNT
  311.         MOV     BX,WORD PTR INHANDLE    ;GET FILE HANDLE
  312.         MOV     DX,0
  313.         MOV     CX,0
  314.         MOV     AL,2
  315.         MOV     AH,LSEEK
  316.         INT     DOS                     ;SEEK TO END OF FILE
  317.         MOV     WORD PTR SIZEHI,DX
  318.         MOV     WORD PTR SIZELO,AX      ;SAVE FILE SIZE
  319.         CMP     DX,0
  320.         JNE     BIG                     ;IF HI WORD >0
  321.         CMP     AX,0
  322.         JNE     L_11
  323.         JMP     CLOSEFILE               ;IF FILE SIZE 0, JUST EXIT
  324. L_11:
  325.         CMP     AX,INBUFSIZE
  326.         JC      SMALL                   ;IF FILE SIZE < BUFFER SIZE
  327. BIG:
  328.         SUB     AX,INBUFSIZE
  329.         JNB     NOBORROW
  330.         DEC     DX
  331. NOBORROW:
  332.         MOV     CX,DX                   ;CX = MSW OF OFFSET
  333.         MOV     DX,AX                   ;DX = LSW OF OFFSET
  334.         MOV     BX,WORD PTR INHANDLE
  335.         MOV     AL,0
  336.         MOV     AH,LSEEK
  337.         INT     DOS                     ;MOVE FILE POINTER BACK BY BUFSIZ
  338.     MOV    WORD PTR POSHI,DX    ;SAVE HI WORD OF POSITION
  339.     MOV    WORD PTR POSLO,AX    ;SAVE LO WORD OF POSITION
  340.         JMP     FILLBUF
  341. SMALL:
  342.         MOV     CX,0
  343.         MOV     DX,0
  344.         MOV     AL,0
  345.         MOV     BX,WORD PTR INHANDLE
  346.         MOV     AH,LSEEK
  347.         INT     DOS                     ;REWIND TO START OF FILE
  348.     MOV    BYTE PTR ATSTART,1    ;SET "AT START" FLAG
  349. FILLBUF:
  350.         MOV     CX,WORD PTR AMTTOREAD   ;CX = # BYTES TO READ
  351.         MOV     BX,WORD PTR INHANDLE    ;BX = FILE HANDLE
  352.         MOV     DX,OFFSET INBUF            ;OFFSET TO BUFFER
  353.         MOV     AH,READ
  354.         INT     DOS                     ;FILL BUFFER FROM FILE
  355.         JNB    READOK            ;IF NO ERROR
  356.     JMP    BADREAD            ;IF READ ERROR
  357. READOK:
  358.         MOV     WORD PTR NREAD,AX       ;SAVE # BYTES READ
  359.         MOV     CX,AX
  360.         MOV     BX,OFFSET INBUF
  361. SRCEND:
  362.         MOV     AL,BYTE PTR [BX]
  363.         CMP     AL,CTRL$Z
  364.         JE      FOUND                   ;IF ^Z FOUND
  365.         INC     BX
  366.         LOOP    SRCEND
  367. FOUND:
  368.         MOV     WORD PTR ENDTXT,BX      ;SAVE ADDRESS OF END OF TEXT
  369.                                         ;(ACTUALLY, OFFSET FR. DATA SEGMENT)
  370.     JMP    SHORT SRC1
  371. SRC:    DEC    BX
  372. SRC1:
  373.         CMP     BX,OFFSET INBUF         ;AT START OF BUFFER?
  374.         JE      NEWBUF            ;YES, BACK UP FURTHER (IF POSSIBLE)
  375.         MOV     AL,BYTE PTR [BX]         ;GET BYTE
  376.         CMP     AL,CR            ;IF NOT CR,
  377.     JNE    SRC            ;LOOP
  378.  
  379.     MOV    AX,1            ;FOUND CR,
  380.     SUB    WORD PTR NUMCNT,AX    ;COUNT 1 LINE
  381.     JNB    SRC            ;LOOP IF COUNT STILL >0
  382.         ADD    BX,2                    ;START OF RIGHT LINE FOUND, SKIP CR/LF
  383.     JMP    BEGIN            ;BEGIN OUTPUT
  384.  
  385. NEWBUF: CMP    BYTE PTR ATSTART,0    ;SEE IF WE CAN BACK UP MORE
  386.     JNE    BEGIN            ;NO, WE CAN'T
  387.     MOV    AX,WORD PTR POSLO    ;GET LO WORD OF FILE POSITION
  388.     SUB    AX,INBUFSIZE        ;SUBTRACT BUFFER SIZE
  389.     MOV    BX,WORD PTR POSHI    ;GET HI WORD OF FILE POSITION
  390.     SBB    BX,0            ;IF 'C' FLAG SET, SUBTRACT 1
  391.     JB    TOOFAR            ;IF <1 BUFFER LEFT TO GO
  392.     MOV    CX,BX
  393.     MOV    DX,AX            ;OFFSET IN CX:DX
  394.     MOV    BX,WORD PTR INHANDLE
  395.     MOV    AL,0
  396.     MOV    AH,LSEEK
  397.     INT    DOS            ;MOVE FILE POINTER BACK
  398.     MOV    WORD PTR POSHI,DX
  399.     MOV    WORD PTR POSLO,AX    ;SAVE NEW POSITION    
  400.     JMP    FILLBUF            ;GO FILL BUFFER AGAIN
  401.  
  402. ;    COME HERE WHEN <1 FULL BUFFER REMAINS TO BE READ
  403.  
  404. TOOFAR:    MOV    AX,WORD PTR POSLO
  405.     MOV    WORD PTR AMTTOREAD,AX    ;SET AMT TO READ = AMOUNT UNREAD
  406.     MOV    CX,0    
  407.     MOV    DX,0            ;MOVE TO START OF FILE
  408.     MOV    BX,WORD PTR INHANDLE
  409.     MOV    AL,0
  410.     MOV    AH,LSEEK
  411.     INT    DOS            ;SEEK TO START
  412.     MOV    BYTE PTR ATSTART,1    ;SET "AT START" FLAG
  413.     JMP    FILLBUF            ;GO FILL BUFFER
  414.  
  415. ;    READY TO OUTPUT LINE(S)
  416.  
  417. BEGIN:
  418.         MOV     DX,WORD PTR ENDTXT      ;GET END OF TEXT IN DX
  419. SHOW:   CMP     DX,BX                   ;DISPLAY TEXT - TOP OF LOOP
  420.         JE    ENDBUF             ;UNTIL END OF BUFFER
  421.         MOV     AL,BYTE PTR [BX]
  422.         CALL    WRITEBYTE
  423.     CMP    AL,CTRL$Z        ;QUIT IF ^Z WRITTEN
  424.     JE    DONE
  425.         INC     BX
  426.         JMP     SHOW
  427. ENDBUF:    
  428.         MOV     CX,INBUFSIZE           ;CX = # BYTES TO READ
  429.         MOV     BX,WORD PTR INHANDLE    ;BX = FILE HANDLE
  430.         MOV     DX,0                    ;OFFSET TO BUFFER FROM ES
  431.         MOV     AH,READ
  432.         INT     DOS                     ;FILL BUFFER FROM FILE
  433.         JB    BADREAD            ;IF ERROR
  434.     MOV    DX,AX            ;SAVE BYTES READ
  435.     CMP    AX,0
  436.     JE    DONE            ;DONE IF 0
  437.     MOV    BX,0            ;BX = OFFSET TO START OF BUFFER
  438.     JMP    SHOW            ;OUTPUT SOME MORE
  439.  
  440. BADREAD:
  441.         MOV     DX,OFFSET MSG2
  442.         CALL    ERRORMSG
  443. DONE:
  444. CLOSEFILE:
  445.         MOV     BX,WORD PTR INHANDLE
  446.         MOV     AH,DOS2_CLOSE
  447.         INT     DOS                     ;CLOSE FILE
  448.     CALL    FLUSH            ;FLUSH ANYTHING IN OUTPUT BUFFER
  449.     RET
  450. TAIL    ENDP
  451.  
  452. EXIT2:
  453.         MOV     AH,EXIT
  454.         INT     DOS                     ;EXIT TO DOS
  455.  
  456. ;     WRITE A BYTE TO THE OUTPUT
  457. ;
  458. WRITEBYTE PROC     NEAR
  459.     PUSH    BX
  460.     PUSH    CX
  461.     PUSH    DX
  462.     MOV    BX,WORD PTR OUTNDX
  463.     MOV    BYTE PTR [BX+OUTBUF],AL
  464.     INC    BX
  465.     MOV    WORD PTR OUTNDX,BX
  466.     CMP    BX,OUTBUFSIZE
  467.     JL    NOTFUL
  468.     CALL    FLUSH
  469. NOTFUL:
  470.     POP    DX
  471.     POP    CX
  472.     POP    BX
  473.     RET
  474. WRITEBYTE ENDP
  475.  
  476. ;    FLUSH - WRITE OUTPUT BUFFER 
  477.  
  478. FLUSH    PROC    NEAR
  479.     PUSH    AX
  480.     MOV    CX,WORD PTR OUTNDX
  481.     MOV    DX,OFFSET OUTBUF
  482.     MOV    BX,1
  483.     MOV    AH,WRITE
  484.     INT    DOS        ;WRITE TO OUTPUT
  485.     POP    AX
  486.     MOV    WORD PTR OUTNDX,0
  487.     RET
  488. FLUSH    ENDP
  489.  
  490.         END     ENTRY
  491.  
  492.  
  493.